package com.kvn.mock.local;

import com.google.common.collect.Sets;
import com.kvn.mock.common.Log;
import com.kvn.mock.local.domain.MockByHttpItem;
import com.kvn.mock.local.domain.MockByItem;
import com.kvn.mock.local.domain.MockReturnItem;
import com.kvn.mock.local.processor.MockProcessorFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.util.ClassUtils;

import javax.annotation.Resource;
import java.beans.Introspector;
import java.util.Collection;
import java.util.Set;

/**
 * 3.0 以上版本使用 MockBootstrap 来启动 mock 配置。 3.0 之前使用 {@link MockAspect} 来触发 mock 配置
 * Created by wangzhiyuan on 2018/11/6
 */
public class MockBootstrap implements InitializingBean {
    private static final Logger logger = LoggerFactory.getLogger(MockBootstrap.class);

    @Resource
    private ApplicationContext applicationContext;
    @Resource
    private MockProcessorFactory mockProcessorFactory;

    @Override
    public void afterPropertiesSet() throws Exception {
        DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) applicationContext.getAutowireCapableBeanFactory();
        Collection<MockByItem> mockByItems = MockConfig.MOCKBY_CONFIG_MAP.values();
        Collection<MockReturnItem> mockReturnItems = MockConfig.MOCKRETURN_CONFIG_MAP.values();
        Collection<MockByHttpItem> mockByHttpItems = MockConfig.MOCKBYHTTP_CONFIG_MAP.values();
        Set<Class> mockedClassSet = Sets.newHashSet();
        for (MockByItem item : mockByItems) {
            mockedClassSet.add(item.getMockedClass());
        }
        for (MockReturnItem item : mockReturnItems) {
            mockedClassSet.add(item.getMockedClass());
        }
        for (MockByHttpItem item : mockByHttpItems) {
            mockedClassSet.add(item.getMockedClass());
        }

        // 替换 bean 为 Proxy
        for (Class mockedClass : mockedClassSet) {
            Object bean = beanFactory.getBean(mockedClass);
            String beanName = getDefaultBeanName(mockedClass);
            beanFactory.removeBeanDefinition(beanName);
            beanFactory.registerSingleton(beanName, new MockProxy(bean, mockProcessorFactory).getProxy());
            logger.info(Log.op("register mock proxy").msg("注入 mock proxy bean 替换 bean[{0}]", beanName).toString());
        }

    }

    private String getDefaultBeanName(Class mockedClass) {
        String shortClassName = ClassUtils.getShortName(mockedClass.getCanonicalName());
        return Introspector.decapitalize(shortClassName);
    }
}
